﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;

#if UNITY_EDITOR
using UnityEditor;
#endif

[AddComponentMenu("PUEX/Emitter/CylinderEmitter")]
public class PUEXCylinderEmitter : PUEXEmitter {

	#region - Editable property
	[Header("CylinderEmitter:")]
	public float radiusBottom;
	public float radiusTop;
	public float length;
	public bool emitOnSurface;
	public bool emitLinear;
	public bool flipLinear;
	public bool alignDirection;
	public bool tangentDirection;
	public float randomDeviant;
	public bool flipDirection;
	#endregion
	
	#region - Property
	protected Vector3 _emitOffset;
	protected Vector3 _intersectionP;
	#endregion

	#region - Lifecycle
	public PUEXCylinderEmitter ()
	{
		radiusBottom = 5f;
		radiusTop = 10f;
		length = 20f;
		emitOnSurface = false;
		emitLinear = false;
		flipLinear = false;
		alignDirection = true;
		tangentDirection = false;
		randomDeviant = 0f;
		flipDirection = false;
	}
	#endregion

	#region - Emit
	public override void emitParticles(int requested)
	{
		if (requested > 0 && alignDirection) {
			if (radiusBottom < radiusTop) {
				float d = (length * radiusTop) / (radiusTop - radiusBottom);
				_intersectionP = -Vector3.forward * (d - length);
			} else if (radiusBottom > radiusTop) {
				float d = (length * radiusBottom) / (radiusBottom - radiusTop);
				_intersectionP = Vector3.forward * d;
			}
		}
		
		base.emitParticles(requested);
	}

	protected override void initParticlePosition (PUEXParticle particle, int index, int requested)
	{
		if (emitLinear) {
			float a = timeFraction;
			if (flipLinear)
				a = 1f - timeFraction;
			float z = a * length;
			float r = radiusBottom + a * (radiusTop - radiusBottom);
			if (emitOnSurface == false)
				r = Random.value * r;

			float rad = (float)index / (float)requested * -Mathf.PI * 2f;
			float x = Mathf.Cos (rad) * r;
			float y = Mathf.Sin (rad) * r;
			_emitOffset = new Vector3(x, y, z);
		} else {
			float a = Random.value;
			float z = a * length;
			float r = radiusBottom + a * (radiusTop - radiusBottom);
			if (emitOnSurface == false)
				r = Random.value * r;
			
			Vector2 v2 = Random.insideUnitCircle.normalized * r;
			_emitOffset = new Vector3(v2.x, v2.y, z);
		}

		particle.position = particle.originalPosition = emitterToSimulationTransform.MultiplyPoint (_emitOffset);
	}
	
	protected override void initParticleVelocity (PUEXParticle particle, int index, int requested)
	{
		if (alignDirection) {
			Vector3 dir = Vector3.forward;

			if (radiusBottom < radiusTop) {
				dir = _emitOffset - _intersectionP;
			} else if (radiusBottom > radiusTop) {
				dir = _intersectionP - _emitOffset;
			}
			
			if (tangentDirection) {
				dir = Vector3.Cross (dir, Vector3.forward);
			}
			
			if (randomDeviant > 0f) {
				dir = PUEXUtils.randomDeviant(dir, randomDeviant);
			}
			
			if (flipDirection) {
				dir *= -1f;
			}
			
			particle.direction = particle.originalDirection = emitterToSimulationTransform.MultiplyVector (dir).normalized;
		} else {
			particle.direction = particle.originalDirection = emitterToSimulationTransform.MultiplyVector (Random.insideUnitSphere).normalized;
		}
		
		particle.speed = particle.originalSpeed = startSpeed.getValue (timeFraction);
	}
	#endregion
	
	#region - Draw
	public void OnDrawGizmos()
	{
		if (!enabled)
			return;
		
		#if UNITY_EDITOR
		Matrix4x4 defaultMatrix = Handles.matrix;
		Handles.matrix = transform.localToWorldMatrix;
		
		Color defaultColor = Handles.color;
		Handles.color = Color.blue;
		
		Handles.DrawWireDisc(Vector3.zero, Vector3.forward, radiusBottom);
		Handles.DrawWireDisc(Vector3.forward * length, Vector3.forward, radiusTop);
		Handles.DrawLine(Vector3.left * radiusBottom, Vector3.forward * length + Vector3.left * radiusTop);
		Handles.DrawLine(Vector3.right * radiusBottom, Vector3.forward * length + Vector3.right * radiusTop);
		Handles.DrawLine(Vector3.up * radiusBottom, Vector3.forward * length + Vector3.up * radiusTop);
		Handles.DrawLine(Vector3.down * radiusBottom, Vector3.forward * length + Vector3.down * radiusTop);
		
		Handles.color = defaultColor;
		Handles.matrix = defaultMatrix;
		#endif
	}
	#endregion

	#region - Serialization
	public override JsonData save (JsonData systemData)
	{
		JsonData ret = base.save (systemData);

		ret ["radius_bottom"] = radiusBottom;
		ret ["radius_top"] = radiusTop;
		ret ["length"] = length;
		ret ["emit_on_surface"] = emitOnSurface;
		ret ["emit_linear"] = emitLinear;
		ret ["flip_linear"] = flipLinear;
		ret ["align_direction"] = alignDirection;
		ret ["tangent_direction"] = tangentDirection;
		ret ["random_deviant"] = randomDeviant;
		ret ["flip_direction"] = flipDirection;
		
		return ret;
	}
	#endregion

}
